#ifndef GAMESERVER_H
#define GAMESERVER_H

#include "Game/SocketDefine.h"
#include "Game/GameDefine.h"

#include "_Global/GameModel.h"
#include "_Global/Socket/Server/Server/Server.h"
#include "_Global/Socket/Common.h"
#include "_Global/GlobalClass.h"

#include <QHash>
#include <QWidget>
#include <QTimer>
#include <QCloseEvent>


//#define WAIT_GAME_TERMINATE_TIME 5000



class Database;
class UDPIOCP_Pleafles;


//游戏登录后 用户数据
struct _GameUserData
{
public:
    explicit _GameUserData():
        m_unID(0),
        m_nServerID(-1),
        m_unUserGameID(0),
        m_nSex(-1),
        m_nScore(0),
        m_nVersion(0),
        m_nDuiWu(-1),
        m_nGroupType(-1)
        //m_playID(-1)
    {
        //_pool_init();
    }
    virtual ~_GameUserData()
    {}

    virtual void _pool_init()
    {
        qDebug() << "[GameServer]_GameUserData _pool_init";
    }
    virtual void _pool_release()
    {
        qDebug() << "[GameServer]_GameUserData _pool_release";

        m_unID = 0;
        m_nServerID = -1;
        m_unUserGameID = 0;
        m_nSex = -1;
        m_nDuiWu = -1;
        //m_playID = -1;
        m_nScore = 0;
        m_vExtraData = QVariant();
        m_nVersion = 0;
        m_nGroupType = -1;

        m_strUserName.clear();
        m_strNickName.clear();
    }

public:

public:
//Info数据
    quint32 m_unID;             //客户id(数据库的id号)//void *m_id;
    QString m_strUserName;      //客户登录名

//GameInfo数据
    qint32 m_nServerID;         //服务器ID
    quint32 m_unUserGameID;     //客户游戏号
    QString m_strNickName;
    qint16 m_nSex;
    qint32 m_nScore;
    qint32 m_nVersion;
    QVariant m_vExtraData;

    //QString password;

//游戏数据
    qint16 m_nDuiWu;
    //qint16 m_nPlayID;     //游戏player的下标

    qint32 m_nGroupType;         //玩家选择的房间类型
};



//群
class _GameGroup: public GameModel
{
    Q_OBJECT
public:
    explicit _GameGroup(QObject *parent = nullptr)
        :GameModel(parent)
    {
        m_pClientsGroupInfo = nullptr;
        //InitOnce();
        m_nGroupID = -1;
        //m_vData = QVariant();
        m_nType = -1;
        //_pool_init();
        //_pool_bNew = true;
        m_bResetFrameWhenClientExitGroup = true;
        m_nFrameSendInterval = -1;


        m_bRunAtServer = true;
        m_bLogicalMaster = true;


        connect(&m_timerFrameSend, &QTimer::timeout, this, [=](){
            SendGameFrameData(true);
        });
    }
    virtual ~_GameGroup()
    {
        //if(m_pGameModel != nullptr)
        //    m_pGameModel->TerminateGame(GameModel::Game_Status_Terminated, -1);
        //TerminateGame(GameModel::Game_Status_Terminated, -88);
        sl_OverGame(GameModel::Game_Status_Terminated, -88);

        /*if(isRunning())
        {
            //!!!注意这里,是否需要等待!!!
            if(!wait(WAIT_GAME_TERMINATE_TIME))  //返回true:线程已经退出
            {
                terminate();
            }
            emit s_GameOver(gameStatus(), -1);
        }*/

        //_release();
    }

public:
    virtual void _pool_init()
    {
        qDebug() << "[GameServer]_GameGroup _pool_init";
        if(isRunning())
        {
            sl_OverGame(GameModel::Game_Status_Terminated, -88);
            //terminate();
            //emit s_GameOver();
        }
    }
    virtual void _pool_release()
    {
        qDebug() << "[GameServer]_GameGroup _pool_release";
        m_nGroupID = -1;
        m_vData = QVariant();
        m_nType = -1;
        m_listGameSyncData.clear();
        m_listGameFrameData.clear();
        m_unFrameIndex = 0;
        m_timerFrameSend.stop();
        m_mapClientFrameRecievedFlag.clear();
        m_mapGameSyncAllData.clear();
        sl_OverGame(GameModel::Game_Status_Terminated, -88);
        //TerminateGame(GameModel::Game_Status_Terminated, -1);
        //this->disconnect();
    }


signals:
    //GameCore线程中使用信号来发送
    //void s_SendToGroupAllClients(QByteArray ba, _ClientInfo *pClientInfo);


    void s_Info(QString msg);
    void s_Debug(QString msg);
    void s_Warning(QString msg);
    void s_Critical(QString msg);



//重载框架:
public:
    //一次初始化
    virtual int _InitOnce() Q_DECL_OVERRIDE
    {
        //qDebug() << "[GameGroup]InitOnce";

        int ret = GameModel::_InitOnce();
        if(ret != 0)
            return ret;

        return ret;
    }

    //初始化
    virtual int _GameInit(int sr = -1, QVariantMap param = QVariantMap()) Q_DECL_OVERRIDE
    {
        qDebug() << "[GameGroup]GameInit";
        int ret = GameModel::_GameInit(sr, param);

        /*if(m_pGameModel != nullptr)
        {
            ret = m_pGameModel->GameInit(sr, param);
            createRandomNumberAndSend(100);
            emit m_pGameModel->s_GameInitFinished();
            return ret;
        }
        else
            return -1;

        return ret;*/


        if(ret != 0)
            return ret;


        if(m_nFrameSendInterval > 0)
        {
            m_timerFrameSend.setInterval(m_nFrameSendInterval);
            m_timerFrameSend.start();
        }
        m_unFrameIndex = 0;
        m_listGameSyncData.clear();
        m_listGameFrameData.clear();
        m_mapClientFrameRecievedFlag.clear();
        m_mapGameSyncAllData.clear();


        createRandomNumberAndSend(1000, 0);

        return ret;


        //m_mutexUserAction.tryLock();
        //m_mutexNet.tryLock();
        //releaseDataList();

        /*
        while(!dataList.isEmpty())
        {
            delete dataList.takeFirst();
        }*/
        //m_Producer.init();

        //param["0"] = QVariant::fromValue<void*>(m_GameNormalLogical.m_listPets.at(0));

    }

    //强制结束游戏,并群发给所有客户
    virtual GameModel::_GameStatus _TerminateGame(GameModel::_GameStatus status = GameModel::Game_Status_Terminated, qint32 code = 0) Q_DECL_OVERRIDE
    {
        //if(m_pGameModel != nullptr)
        {
            if(!isRunning())
                return gameStatus();


            GameModel::_GameStatus ret = GameModel::_TerminateGame(status, code);
            //quit();



            /*
            if(!wait(WAIT_GAME_TERMINATE_TIME))  //返回true:线程已经退出
            {
                terminate();
            }*/


            //sl_UserActionFinished();
            return ret;
        }
        //else
        //    return GameModel::Game_Status_Terminated;
    }




//服务器函数(主线程)
public:
    //服务器游戏准备开始
    //进行初始化,并给客户端发送初始化数据，等待客户初始化完毕
    //参数：type:0等待所有人准备；1强制开始
    //返回：0:正常;-1:玩家为空!;-2:已经是Playing;-3:有人没准备好!
    int StartGame(int type = 0);
    //服务器游戏结束处理
    void GameOver(GameModel::_GameStatus status, qint32 code)
    {
        //if(m_pGameModel != nullptr)
            emit s_Info(tr("[GameGroup]房间游戏结束:%1(%2),%3(%4)")
                   .arg(m_nGroupID)
                   .arg(m_pClientsGroupInfo->m_uuid.toString())
                   .arg(status)
                   .arg(code)
                   );

        m_pClientsGroupInfo->m_flagStatus &= ~_ClientsGroupInfo::Status_Playing;
        while(!m_pClientsGroupInfo->m_mapDisconnectClientData.isEmpty())
        {
            qint32 oldGroupIndex = m_pClientsGroupInfo->m_mapDisconnectClientData.firstKey();
            //qint32 oldSocketID = m_pClientsGroupInfo->m_mapDisconnectClientData.take(oldGroupIndex);
            m_pClientsGroupInfo->ReleaseGroupIndex(oldGroupIndex);
        }

        QMap<qint32, _ClientInfo*>::const_iterator ii;
        for(ii = m_pClientsGroupInfo->m_mapAllClients.constBegin(); ii != m_pClientsGroupInfo->m_mapAllClients.constEnd(); ++ii)
        {
            switch((*ii)->m_ClientGroupStatus)
            {
            case _ClientGroupStatus::GroupStatus_Waiting:
            case _ClientGroupStatus::GroupStatus_Readying:
            case _ClientGroupStatus::GroupStatus_Playing:
            case _ClientGroupStatus::GroupStatus_ReJoining:
                if(m_pClientsGroupInfo->m_pGroupMaster == (*ii))
                    (*ii)->ChangeGroupStatus(_ClientGroupStatus::GroupStatus_Readying);
                else
                    (*ii)->ChangeGroupStatus(_ClientGroupStatus::GroupStatus_Waiting);
                break;
            case _ClientGroupStatus::GroupStatus_ReadyToWatch:
                continue;
            case _ClientGroupStatus::GroupStatus_Watching:
                (*ii)->m_ClientGroupStatus = GroupStatus_ReadyToWatch;
                continue;
            default:
                emit s_Warning(tr("[!GameGroup]GameOver Client Status WARNING!"));
            }


        }

        //如果不是正常结束
        //if(status !=  GameModel::Game_Status_GameOver)
        {
            //发送
            QByteArray ba = m_pClientsGroupInfo->m_pIOCP->newSendData(TRANSMIT_GAME_TYPE);
            QDataStream ds(&ba,QIODevice::ReadWrite);
            ds.device()->seek(ba.size());
            ds << (qint16)GAME_DATA
               << (qint16)GAME_DATA_GAMEOVER
               << (qint16)status
               << code
               //<< playerJiaoSeList
                  ;
            m_pClientsGroupInfo->m_pIOCP->CorrectDataLength(ba);
            m_pClientsGroupInfo->SendToGroupAllClients(ba, nullptr);
        }


        m_timerFrameSend.stop();
        m_unFrameIndex = 0;

        m_listGameSyncData.clear();
        m_listGameFrameData.clear();
        m_mapClientFrameRecievedFlag.clear();
        //m_bResetFrameWhenClientExitGroup = true;
        m_mapGameSyncAllData.clear();

    }



//游戏逻辑：可重写
    //游戏真正开始
    virtual GameModel::_GameStatus _GameStart(bool isStarted) Q_DECL_OVERRIDE
    {
        GameModel::_GameStatus ret = GameModel::_GameStart(isStarted);

        if(ret != GameModel::Game_Status_Running)
            return ret;


        /*
        QMap<qint32, _ClientInfo*>::const_iterator ii;
        for(ii = m_pClientsGroupInfo->m_mapAllClients.constBegin(); ii != m_pClientsGroupInfo->m_mapAllClients.constEnd(); ++ii)
        {
            (*ii)->m_ClientGroupStatus = GroupStatus_Playing;
        }*/

        /*GameModel::_GameStatus ret = GameModel::Game_Status_ERROR;
        if(m_pGameModel != nullptr)
        {
            m_pGameModel->m_eGameStatus = GameModel::Game_Status_Running;

            emit m_pGameModel->s_GameBegin();
            return m_pGameModel->gameStatus();
        }
        return ret;
        */

        //m_pClientsGroupInfo->m_flagStatus |= _ClientsGroupInfo::Status_Locked;

        return ret;
    }

    virtual int _OverGame(_GameStatus status = Game_Status_GameOver, qint32 code = 0) Q_DECL_OVERRIDE
    {
        return GameModel::_OverGame(status, code);
    }




    //联网游戏准备结束
    virtual int OverGame(GameModel::_GameStatus status, qint32 code, _ClientInfo *pClientInfo)
    {
        int ret = 0;
        switch(status)
        {
        case GameModel::Game_Status_GameOver:
            ret = 0;
            //房主来结束游戏
            if(m_pClientsGroupInfo->m_pGroupMaster == pClientInfo)
                sl_OverGame(status, code);

            break;
        case GameModel::Game_Status_ERROR:
        case GameModel::Game_Status_Terminated:
            ret = -1;
            sl_OverGame(status, code);
            break;
        default:
            ret = -2;
            sl_OverGame(status, code);
        }

        return ret;
    }





//帧函数
//大体分为两种模式:
//  1是所有客户端同步,所有Playing的客户发送帧后进行帧转发,然后进行下一帧,推荐(但一卡都卡)
//  2是所有客户端不同步,由服务端定时发送帧数据,每个客户端不必须每帧发送帧数据,但发送的帧数据由服务端加上帧标志(index)后转发,客户端运行到index帧后进行处理.
//    不推荐,若有卡机,延迟很严重的话完全不同步(即时战略可以考虑使用),如果用这个方案,因为服务器无法用frameIndex识别无效帧,所以客户推出不会清空原帧数据,其他客户端必须做好某客户退出操作
//    这种情况,适合只用Frame来收发数据,SyncData可以不用.
//简单原理:
//  游戏开始后,Master获取随机数序列,将AllData,随机数数据 转发给其他客户,所有客户状态为Playing或Watching
//  所有Playing客户进行数据修改,同步至服务器和所有客户端之间(进行数据差异合并),下一帧开始时由Master发送合并后的所有游戏数据和随机数数据
//  所有Playing客户进行帧数据发送,服务器收集后一次性全部转发给所有客户,客户进行识别和操作,然后进入下一帧
//  半途加入的客户,收到此帧的AllData和随机数数据 后,改变状态正式加入游戏
//  半途退出的客户,由配置m_bResetFrameWhenClientExitGroup决定是否清空此次帧数据(如果清空,则必须由客户端重新进行帧操作,一般在Others_JoinGroup消息中识别和操作)
//其他:
//  Frame和SyncData区别:前者是收集后直接一次性转发,后者是即时转发.
//  如果游戏中将房间锁定(中途不可加入客户),则Master可以只在游戏开始时发送一次AllData(给一开始加入的客户同步)即可,其他帧不需要再同步AllData(节省时耗)
//    为防止Master还没发送AllData便退出的情况,其他Client在SetMaster时判断一下帧是否为0和AllData是否为空,来做一次同步.

    //收到一个数据，简单转发给其他客户
    //pTargetClientInfo:nullptr是全部客户(除自己);其他值
    virtual int GameTransferData(QVariantMap data, _ClientInfo *pTargetClientInfo, _ClientInfo *pClientInfo)
    {
        emit s_Debug(tr("[GameGroup]GameTransferData..."));

        if(nullptr == pClientInfo)
        {
            emit s_Critical(tr("[!GameGroup]GameTransferData nullptr ERROR!"));
            return -1;
        }

        if(this->m_pClientsGroupInfo != pClientInfo->m_pGroup)
        {
            emit s_Critical(tr("[!GameGroup]GameTransferData ERROR!"));
            return -1;
        }
        if(!(m_pClientsGroupInfo->m_flagStatus & _ClientsGroupInfo::Status_Playing))
        {
            emit s_Warning(tr("[!GameGroup]GameTransferData NOT Playing ERROR!"));
            return -2;
        }


        _GameUserData *pGameUserData = (_GameUserData*)pClientInfo->m_pClientExtraData;
        //data["__UserGameID"] = ((_GameUserData*)pClientInfo->m_pClientExtraData)->m_unUserGameID;

        //转发
        QByteArray ba = m_pClientsGroupInfo->m_pIOCP->newSendData(TRANSMIT_GAME_TYPE);
        QDataStream ds(&ba,QIODevice::WriteOnly | QIODevice::Append);
        ds << (qint16)GAME_DATA
           << (qint16)GAME_DATA_TRANSFER_DATA
           << pGameUserData->m_unUserGameID
           << data
              ;
        m_pClientsGroupInfo->m_pIOCP->CorrectDataLength(ba);

        if(pTargetClientInfo == nullptr)    //发送全部
        {
            m_pClientsGroupInfo->SendToGroupAllClients(ba, pClientInfo);
        }
        else    //发送给单个Client
        {
            m_pClientsGroupInfo->m_pIOCP->send(pTargetClientInfo->m_SocketContext, ba);
        }

        emit s_Debug(tr("[GameGroup]GameTransferData:%1").arg(pGameUserData->m_strNickName));

        return 0;
    }

    //收到一个数据，一帧之内保证全部转发(不管是否是半途进来的客户,包括自己)（一般同步数据用）
    int GameSyncData(QVariantMap data, _ClientInfo *pClientInfo)
    {
        emit s_Debug(tr("[GameGroup]GameSyncData..."));

        if(nullptr == pClientInfo)
        {
            emit s_Critical(tr("[!GameGroup]GameSyncData nullptr ERROR!"));
            return -1;
        }

        if(this->m_pClientsGroupInfo != pClientInfo->m_pGroup)
        {
            emit s_Critical(tr("[!GameGroup]GameSyncData ERROR!"));
            return -1;
        }
        if(!(m_pClientsGroupInfo->m_flagStatus & _ClientsGroupInfo::Status_Playing))
        {
            emit s_Warning(tr("[!GameGroup]GameSyncData Group NOT Playing ERROR!"));
            return -2;
        }
        if(pClientInfo->m_ClientGroupStatus != GroupStatus_Playing)
        {
            emit s_Warning(tr("[!GameGroup]GameSyncData Client NOT Playing ERROR!"));
            return -3;
        }


        _GameUserData *pGameUserData = (_GameUserData*)pClientInfo->m_pClientExtraData;
        //data["__UserGameID"] = ((_GameUserData*)pClientInfo->m_pClientExtraData)->m_unUserGameID;
        m_listGameSyncData << data;


        //转发
        QByteArray ba = m_pClientsGroupInfo->m_pIOCP->newSendData(TRANSMIT_GAME_TYPE);
        QDataStream ds(&ba,QIODevice::WriteOnly | QIODevice::Append);
        ds << (qint16)GAME_DATA
           << (qint16)GAME_DATA_SYNC_DATA
           << pGameUserData->m_unUserGameID
           << data
              ;
        m_pClientsGroupInfo->m_pIOCP->CorrectDataLength(ba);
        //m_pClientsGroupInfo->SendToGroupAllClients(ba, pClientInfo);
        QMap<qint32, _ClientInfo*>::const_iterator ii;
        for(ii = m_pClientsGroupInfo->m_mapAllClients.constBegin(); ii != m_pClientsGroupInfo->m_mapAllClients.constEnd(); ++ii)
        {
            if((*ii)->m_ClientGroupStatus == GroupStatus_Playing
                    || (*ii)->m_ClientGroupStatus == GroupStatus_Watching
                    )
                m_pClientsGroupInfo->m_pIOCP->send((*ii)->m_SocketContext, ba);
        }

        emit s_Debug(tr("[GameGroup]GameSyncData:%1").arg(pGameUserData->m_strNickName));
        return 0;
    }

    //收到 帧数据,简单进行校验
    //将每个Playing的客户收集并调用SendGameFrameData，一般操作数据用
    int GameFrameData(qint32 randomNumberID, qint32 randomNumberPoint, quint32 frameIndex, QVariantMap data, _ClientInfo *pClientInfo)
    {
        emit s_Debug(tr("[GameGroup]GameFrameData..."));

        if(nullptr == pClientInfo)
        {
            emit s_Critical(tr("[!GameGroup]GameFrameData nullptr ERROR!"));
            return -1;
        }

        if(this->m_pClientsGroupInfo != pClientInfo->m_pGroup)
        {
            emit s_Critical(tr("[!GameGroup]GameFrameData ERROR!"));
            return -1;
        }
        if(!(m_pClientsGroupInfo->m_flagStatus & _ClientsGroupInfo::Status_Playing))
        {
            emit s_Warning(tr("[!GameGroup]GameFrameData Group NOT Playing ERROR!"));
            return -2;
        }
        if(pClientInfo->m_ClientGroupStatus != GroupStatus_Playing)
        {
            emit s_Warning(tr("[!GameGroup]GameFrameData Client NOT Playing ERROR:%1").arg(pClientInfo->m_ClientGroupStatus));
            return -3;
        }

        _GameUserData *pGameUserData = (_GameUserData*)pClientInfo->m_pClientExtraData;

        //如果是 同步帧 的方式(第一种方式):
        if(m_nFrameSendInterval <= 0)
        {
            if(frameIndex != m_unFrameIndex)
            {
                emit s_Warning(tr("[!GameGroup]GameFrameData FrameIndex WARNING:%1,%2").arg(frameIndex).arg(m_unFrameIndex));
                return -2;
            }
            if(randomNumberID != m_pClientsGroupInfo->m_RandomNumber.m_nRandomNumberID)
            {
                emit s_Critical(tr("[!GameGroup]GameFrameData RandomID ERROR:%1,%2").arg(randomNumberID).arg(m_pClientsGroupInfo->m_RandomNumber.m_nRandomNumberID));
                return -2;
            }
            if(randomNumberPoint != m_pClientsGroupInfo->m_RandomNumber.m_nUsePoint)
            {
                emit s_Critical(tr("[!GameGroup]GameFrameData RandomPoint ERROR:%1,%2").arg(randomNumberPoint).arg(m_pClientsGroupInfo->m_RandomNumber.m_nUsePoint));
                return -3;
            }
        }


        //data["__UserGameID"] = ((_GameUserData*)pClientInfo->m_pClientExtraData)->m_unUserGameID;
        if(m_mapClientFrameRecievedFlag.contains(pGameUserData->m_unUserGameID))
            m_mapClientFrameRecievedFlag[pGameUserData->m_unUserGameID]++;
        else
            m_mapClientFrameRecievedFlag[pGameUserData->m_unUserGameID] = 1;

        m_listGameFrameData << data;

        emit s_Debug(tr("[GameGroup]GameFrameData:%1,%2").arg(pGameUserData->m_strNickName).arg(randomNumberID));

        return SendGameFrameData(false);
    }
    //发送帧数据
    //forceSend:true,不进行每个客户是否发送判断,直接有多少发送多少(由定时器调用,是第二种游戏模式)
    int SendGameFrameData(bool forceSend)
    {
        emit s_Debug(tr("[GameGroup]SendGameFrameData..."));

        //等待重连的客户
        if(!m_pClientsGroupInfo->m_mapDisconnectClientData.isEmpty())
        {
            emit s_Debug(tr("[GameGroup]SendGameFrameData Waiting..."));
            return 1;
        }

        //int count = 0;
        if(!forceSend)
        {
            QMap<qint32, _ClientInfo*>::const_iterator ii;
            for(ii = m_pClientsGroupInfo->m_mapPlayingClients.constBegin(); ii != m_pClientsGroupInfo->m_mapPlayingClients.constEnd(); ++ii)
            {
                //只统计 Playing 的
                if((*ii)->m_ClientGroupStatus != GroupStatus_Playing)
                    continue;

                //还没有客户端发送帧
                if(!m_mapClientFrameRecievedFlag.contains(((_GameUserData*)((*ii)->m_pClientExtraData))->m_unUserGameID))
                {
                    emit s_Debug(tr("[GameGroup]SendGameFrameData2..."));
                    return 2;
                }

                //count++;
            }
            /*/不足
            if(count > m_listGameFrameData.length())
                return 1;
            else if(count < m_listGameFrameData.length())
            {
                emit s_Critical(tr("[!GameGroup]GameFrameData count ERROR!"));
                return -1;
            }*/
        }


        QByteArray ba = m_pClientsGroupInfo->m_pIOCP->newSendData(TRANSMIT_GAME_TYPE);
        QDataStream ds(&ba,QIODevice::WriteOnly | QIODevice::Append);
        ds << (qint16)GAME_DATA
           << (qint16)GAME_DATA_FRAME_DATA
           << m_unFrameIndex
           << m_listGameFrameData
              ;
        m_pClientsGroupInfo->m_pIOCP->CorrectDataLength(ba);
        m_pClientsGroupInfo->SendToGroupAllClients(ba);
        /*
        for(ii = m_pClientsGroupInfo->m_mapPlayingClients.constBegin(); ii != m_pClientsGroupInfo->m_mapPlayingClients.constEnd(); ++ii)
        {
            //if((*ii)->m_ClientGroupStatus != GroupStatus_Playing)
            {
                m_pClientsGroupInfo->m_pIOCP->send((*ii)->m_SocketContext, ba);
            }
        }*/

        m_unFrameIndex++;
        m_listGameFrameData.clear();
        m_mapClientFrameRecievedFlag.clear();
        m_listGameSyncData.clear();
        m_mapGameSyncAllData.clear();

        emit s_Debug(tr("[GameGroup]SendGameFrameData OK!"));

        return 0;
    }

    //收到一帧的所有游戏数据,并暂存
    //每一帧结束后,所有客户应当合并所有数据改动,并由Master发送给服务端进行暂存(发送给半途加入的玩家),帧转发结束后清空
    int GameSyncAllData(QVariantMap data, qint32 randomNumberPoint, _ClientInfo *pClientInfo)
    {
        emit s_Debug(tr("[GameGroup]GameSyncAllData..."));

        if(m_pClientsGroupInfo->m_pGroupMaster == pClientInfo)
        {
            pClientInfo->m_ClientGroupStatus = GroupStatus_Playing;
        }
        else
        {
            emit s_Warning(tr("[!GameGroup]GameSyncAllData Master WARNING:%1,%2")
                           .arg((int)m_pClientsGroupInfo->m_pGroupMaster)
                           .arg((int)pClientInfo)
                           );
        }

        if(!(m_pClientsGroupInfo->m_flagStatus & _ClientsGroupInfo::Status_Playing))
        {
            emit s_Warning(tr("[!GameGroup]GameSyncAllData NOT Playing ERROR!"));
            return -2;
        }

        if(!m_mapGameSyncAllData.isEmpty())
            emit s_Warning(tr("[!GameGroup]GameSyncAllData DATA IS NOT EMPTY WARNING!"));


        _GameUserData *pGameUserData = (_GameUserData*)pClientInfo->m_pClientExtraData;

        m_pClientsGroupInfo->m_RandomNumber.m_nUsePoint = randomNumberPoint;
        m_mapGameSyncAllData = data;


        int count = 0;

        QMap<qint32, _ClientInfo*>::const_iterator ii;
        for(ii = m_pClientsGroupInfo->m_mapAllClients.constBegin(); ii != m_pClientsGroupInfo->m_mapAllClients.constEnd(); ++ii)
        {
            switch ((*ii)->m_ClientGroupStatus) {
            case GroupStatus_Waiting:
            case GroupStatus_Readying:
            case GroupStatus_ReadyToWatch:
            case GroupStatus_ReJoining:
                SendGameSyncAllData(*ii);
                count++;
                break;
            case GroupStatus_Playing:
            default:
                break;
            }
        }

        emit s_Debug(tr("[GameGroup]GameSyncAllData:%1,%2").arg(pGameUserData->m_strNickName).arg(randomNumberPoint));
        return count;
    }

    //给客户发送所有同步数据,包括游戏所有数据,此帧内数据的改动,帧序,随机数数据
    //游戏新开始时给所有非Master发送一次,半途加入的客户发送一次,发送后改变客户状态
    int SendGameSyncAllData(_ClientInfo *pClientInfo)
    {
        emit s_Debug(tr("[GameGroup]SendGameSyncAllData..."));

        if(pClientInfo->m_ClientGroupStatus == GroupStatus_Playing || pClientInfo->m_ClientGroupStatus == GroupStatus_Watching) //如果已经玩状态
            return -1;
        if(!(m_pClientsGroupInfo->m_flagStatus & _ClientsGroupInfo::Status_Playing))
        {
            emit s_Warning(tr("[!GameGroup]SendGameSyncAllData NOT Playing ERROR!"));
            return -2;
        }

        if(pClientInfo == m_pClientsGroupInfo->m_pGroupMaster)  //房主不发
        {
            emit s_Debug(tr("[GameGroup]SendGameSyncAllData Master"));
            return -3;
        }
        if(m_mapGameSyncAllData.isEmpty())      //不存在同步数据
        {
            emit s_Debug(tr("[GameGroup]SendGameSyncAllData is EMPTY"));
            return 1;
        }


        _GameUserData *pGameUserData = (_GameUserData*)pClientInfo->m_pClientExtraData;


        m_pClientsGroupInfo->m_pIOCP->sendData(pClientInfo, TRANSMIT_GAME_TYPE)
                << (qint16)GAME_DATA
                << (qint16)GAME_DATA_SYNC_ALLDATA
                << m_unFrameIndex
                << m_pClientsGroupInfo->m_RandomNumber
                << m_mapGameSyncAllData
                << m_listGameSyncData
                << m_mapClientFrameRecievedFlag.value(pGameUserData->m_unUserGameID, 0)
                   ;
        m_pClientsGroupInfo->m_pIOCP->send(pClientInfo);

        if(pClientInfo->m_ClientGroupStatus == GroupStatus_ReadyToWatch)
            pClientInfo->m_ClientGroupStatus = GroupStatus_Watching;
        else if(pClientInfo->m_ClientGroupStatus != GroupStatus_Nothing)
            pClientInfo->m_ClientGroupStatus = GroupStatus_Playing;
        else
            emit s_Warning(tr("[!GameGroup]SendGameSyncAllData WARNING:%1").arg(pClientInfo->m_ClientGroupStatus));

        emit s_Debug(tr("[GameGroup]SendGameSyncAllData:%1").arg(pGameUserData->m_strNickName));
        return 0;
    }


    //客户退出正在运行的游戏
    //两种方案:1是重新让客户进行一次帧;2是直接判断并发送帧(这种必须在客户端内进行正确的判断和操作)
    virtual int ClientExitRunningGroup(qint32 oldGroupIndex, quint32 oldUserGameID)
    {
        //((_GameGroup*)pGroup->m_pClientsGroupExtraData)->sl_OverGame(GameModel::Game_Status_Terminated, -1);
        //CorrectFrameAndData(oldUserGameID);
        QVariantMap map;
        map["__UserGameID"] = oldUserGameID;
        map["__SocketID"] = -1;
        map["__GroupIndex"] = oldGroupIndex;
        map["__Type"] = 0;
        map["__Value"] = 1;

        GameSyncData(map, m_pClientsGroupInfo->m_pGroupMaster);


        if(m_nFrameSendInterval <= 0)
        {
            if(m_bResetFrameWhenClientExitGroup)
            {
                m_listGameFrameData.clear();            //清除帧（有可能含有离开房间玩家的信息）
                m_mapClientFrameRecievedFlag.clear();
            }
            else
            {
                SendGameFrameData(false);
            }
        }

        /*
        for(int i = 0; i < m_listGameSyncData.length();)
        {
            if(m_listGameSyncData.at(i).toMap().value("__SocketID").toInt() == pClientInfo->m_SocketContext.nSocketID)
            {
                m_listGameSyncData.removeAt(i);
                continue;
            }
            i++;
        }*/

        return 0;
    }



    /*int CorrectFrameAndData(quint32 oldUserGameID)
    {
        QVariantList::iterator ii;
        for(ii = m_listGameSyncData.begin(); ii != m_listGameSyncData.end(); ++ii)
        {
            QVariantMap v = (*ii).toMap();
            if(v.value("__UserGameID") == oldUserGameID)
            {
                v["__UserGameID"] = newSocketID;
                (*ii) = v;
            }
        }

        for(ii = m_listGameFrameData.begin(); ii != m_listGameFrameData.end(); ++ii)
        {
            QVariantMap v = (*ii).toMap();
            if(v.value("__UserGameID") == oldSocketID)
            {
                v["__UserGameID"] = newSocketID;
                (*ii) = v;
            }
        }

        for(ii = m_mapGameSyncAllData.begin(); ii != m_mapGameSyncAllData.end(); ++ii)
        {
            QVariantMap v = (*ii).toMap();
            if(v.value("__UserGameID") == oldSocketID)
            {
                v["__UserGameID"] = newSocketID;
                (*ii) = v;
            }
        }

        //QVariantMap                 m_mapGameSyncAllData;
    }*/



    //创建并发送随机数
    //type:-1表示给所有人发送,为0表示给Master发送
    void createRandomNumberAndSend(qint32 n = 10000, int type = -1)
    {
        m_pClientsGroupInfo->m_RandomNumber.createRandomNumber(n);

        //发送群里其他客户
        QByteArray ba = m_pClientsGroupInfo->m_pIOCP->newSendData(TRANSMIT_GROUP_TYPE);
        QDataStream ds(&ba,QIODevice::ReadWrite);
        ds.device()->seek(ba.size());
        ds << (qint16)GAME_SERVER_RESPONSE
           << (qint16)GAME_SERVER_GROUP
           << (qint16)GAME_SERVER_GROUP_RANDOMNUMBER
           << m_pClientsGroupInfo->m_RandomNumber;
              ;
        m_pClientsGroupInfo->m_pIOCP->CorrectDataLength(ba);

        if(type == -1)
            m_pClientsGroupInfo->SendToGroupAllClients(ba, nullptr);
        else if(type == 0)
        {
            if(m_pClientsGroupInfo->m_pGroupMaster != nullptr)
            m_pClientsGroupInfo->m_pIOCP->send(m_pClientsGroupInfo->m_pGroupMaster->m_SocketContext, ba);
        }
    }




    /*/封装_ClientsGroupInfo::SendToGroupAllClients
    int SendToGroupAllClients(QByteArray ba, _ClientInfo *pClientInfo = nullptr)
    {
        if(m_pClientsGroupInfo != nullptr)
            return m_pClientsGroupInfo->SendToGroupAllClients(ba, pClientInfo);
        return -1;
    }*/



public:
    //ProducerModel   m_Producer; //生产消费者模式
    qint32      m_nGroupID; //房号(0~999999)

    //GameModel   *m_pGameModel;
    qint32      m_nType;    //游戏类型
    QVariant    m_vData;    //创建房间时的一些额外数据，会给每个Join的玩家发送




public:
//游戏控制
    //每一帧 每个客户端 需要同步的数据（在发送 帧数据 前发送，一般游戏开始或加入游戏后只发送1次，在发送或收到m_mapGameSyncAllData后发送）
    QVariantList                m_listGameSyncData;

    //每一帧的所有数据
    QVariantList                m_listGameFrameData;
    QMap<quint32, qint32>       m_mapClientFrameRecievedFlag;           //每个客户是否发送了帧<userGameID,times>
    bool                        m_bResetFrameWhenClientExitGroup;       //有客户退出时是否清空帧
    quint32                     m_unFrameIndex;                         //发送的FrameIndex

    //数据副本（由master每帧提供）
    QVariantMap                 m_mapGameSyncAllData;

    //发送帧的间隔,如果<=0,则每个客户必须每一帧都要同步;如果>0,则服务器每过一段时间发送一次帧(不一定要所有客户同步)
    qint32          m_nFrameSendInterval;
    QTimer          m_timerFrameSend;                       //定时器,用来定时发送帧



public:
    //与_ClientsGroupInfo互指,一对一
    _ClientsGroupInfo*  m_pClientsGroupInfo;


protected:

private:
};








namespace Ui {
class GameServer;
}

class GameServer : public QWidget
{
    Q_OBJECT

public:
    /*
    class GameGroupFactory
    {
    public:
        virtual _GameGroup* create()
        {
            return new _GameGroup;
        }
    };
    template<class T>
    class T_GameGroupFactory
    {
    public:
        virtual _GameGroup* create()
        {
            return new T;
        }
    };*/


    enum _ServerType
    {
        Type_InfoServer = 0,
        Type_GameServer = 1
    };


public:
    explicit GameServer(QWidget *parent = nullptr);
    virtual ~GameServer();

    int initOnce();


public:
//Server信号处理
    void onAccept(_SocketInfo::_SocketContext socketContext);
    void onDisconnect(int type, _SocketInfo::_SocketContext socketContext);
    //Server收到Client的数据 的回调函数
    void onReadyRead(QByteArray baData, quint8 controlByte, _SocketInfo::_SocketContext socketContext);
    void onUDPReadyRead(QByteArray baData, SOCKADDR_IN addrinClient);


//服务函数扩展
public:
    //开启IOCP服务器、连接数据库等服务
    bool Start();

    //停止IOCP服务器
    void Stop();

    //退出服务器时会最后发送事件来调用这个函数（目的是将事件队列全部处理完毕）
    Q_INVOKABLE void __Exit();

    //停止IOCP服务器后，IOCP会回调这函数，然后再停止数据库等连接
    Q_INVOKABLE void __StopCallback();
    Q_INVOKABLE void __StopCallback_UDP();


public:
//事件重写
    bool event(QEvent *event) override
    {
        switch (event->type())
        {
        case QEvent::Close:
            //qDebug() << "event" << event->type();
            //event->ignore();
            //qApp->exit(0);
            /*QMetaObject::invokeMethod(qApp
                                      , "quit"
                                      , Qt::QueuedConnection
                                      //, Q_ARG(int, 0)
                                      );
            QMetaObject::invokeMethod(qApp
                                      , "exit"
                                      , Qt::QueuedConnection
                                      , Q_ARG(int, 0)
                                      );*/

            //return false;
            break;
        default:
            break;
        }
        return QWidget::event(event);
    }

    void closeEvent(QCloseEvent *event) override
    {
        Stop();

        QMetaObject::invokeMethod(this
                                    , "__Exit"
                                    , Qt::QueuedConnection
                                    //, Q_ARG(int, 0)
                                    );

        //qDebug() << "closeEvent" << event->type();
        event->ignore();
    }


public:
//群函数扩展
    //创建一个群(检测groupID可用性),返回<0错误,正确返回groupID
    qint32 CreateGroup(_ClientInfo *pClientInfo, qint32 playerMaxCount, qint32 playerWatchingMaxCount, QString password, qint32 groupID, qint32 type, QVariant vData);


    //加入群,没有找到返回<0;正常返回 0
    //会换房主
    //groupID为0，则随机加入
    //JoinType:0(玩);1(观看)
    int JoinGroup(_ClientInfo* pClientInfo, qint32 groupID, const QString& password = "", qint32 joinType = 0);

    int ReJoinRunningGroup(_ClientInfo* pClientInfo, qint32 oldGroupIndex, qint32 oldSocketID, qint32 groupID)
    {
        _GameUserData *pGameUserData = (_GameUserData*)(pClientInfo->m_pClientExtraData);

        QUuid uuid = m_hashNumberGroups.value(groupID, QUuid());
        _ClientsGroupInfo* pGroup = m_Server.GetGroup(uuid);
        //qint32 oldSocketID1;
        int ret;

        if(pGroup == nullptr)      //先找群,如果没有 原来加的群
        {
            ret = -1;
        }
        else
        {
            if(!pGroup->m_mapDisconnectClientData.contains(oldGroupIndex))     //如果 断开缓存列表 里没有
            {
                //如果服务器没来得及释放
                _ClientInfo *pOldClientInfo = pGroup->m_mapPlayingClients.value(oldSocketID, nullptr);
                if(pOldClientInfo == nullptr)   //如果正在玩的里没有
                {
                    ret = -3;
                }
                else
                {
                    if(oldSocketID == pOldClientInfo->m_SocketContext.nSocketID)
                    {
                        ret = 0;

                        ExitGroup(pOldClientInfo, true, false);
                        DisconnectClient(pClientInfo, 1);
                    }
                    else
                        ret = -4;
                }
            }
            else
            {
                QVariant oldUserGameID = pGroup->m_mapDisconnectClientData.take(oldGroupIndex);
                if(pGameUserData->m_unUserGameID == (quint32)oldUserGameID.toUInt())
                {
                    ret = 0;
                }
                else
                {
                    qWarning() << "[!GameServer]WARNING:oldUserGameID != UserGameID" << oldUserGameID << pGameUserData->m_unUserGameID;
                    ret = -5;
                }

            }
            if(ret == 0)
            {
                pGroup->ReJoinRunningGroup(pClientInfo, oldGroupIndex);
                pClientInfo->ChangeGroupStatus(_ClientGroupStatus::GroupStatus_ReJoining);
                //((_GameGroup*)pGroup->m_pClientsGroupExtraData)->CorrectFrameAndData(pClientInfo->m_SocketContext.nSocketID, oldSocketID);
                //((_GameGroup*)pGroup->m_pClientsGroupExtraData)->SendGameFrameData(false);
            }

        }
        return ret;
    }

    //释放某个已经掉线的座位
    //返回0正常，<0出错
    int ReleaseGroupIndex(qint32 oldGroupIndex, quint32 oldUserGameID, _ClientsGroupInfo* pGroup)
    {
        if(nullptr == pGroup)
            return -1;

        _GameGroup *pGameGroup = ((_GameGroup*)pGroup->m_pClientsGroupExtraData);

        QVariant data = pGroup->ReleaseGroupIndex(oldGroupIndex);
        if(!data.isValid())
            return -2;

        if(data != oldUserGameID)
            Warning(tr("[GameServer]ReleaseGroupIndex WARNING(%1):%2 != %3").arg(oldGroupIndex).arg(data.toInt()).arg(oldUserGameID));

        //给群内其他客户发送
        QByteArray ba = pGroup->m_pIOCP->newSendData(TRANSMIT_GROUP_TYPE);
        QDataStream ds(&ba,QIODevice::ReadWrite);
        ds.device()->seek(ba.size());
        ds << (qint16)GAME_SERVER_RESPONSE
           << (qint16)GAME_SERVER_GROUP
           << (qint16)GAME_SERVER_GROUP_OTHERSINFO
           << (qint16)GAME_SERVER_GROUP_OTHERSINFO_JOINGROUP
           << (qint32)-1    //oldSocketID
           << oldGroupIndex
           << oldUserGameID
           << pGameGroup->isRunning()
           << pGameGroup->m_bResetFrameWhenClientExitGroup
           << (bool)false       //退出

           << (bool)false       //是否保持Index
              ;
        pGroup->m_pIOCP->CorrectDataLength(ba);
        pGroup->SendToGroupAllClients(ba, nullptr, -1);

        pGameGroup->ClientExitRunningGroup(oldGroupIndex, oldUserGameID);

        return 0;
    }



    //pClientInfo退出群,groupWillClose是否群已经关闭(如果关闭,则不用再次关闭群,也不用群内群发退群信息;如果为false,会群发,并且关闭空群,)
    //bKeepGroupIndex 标识是否保持GroupIndex（断线重连），为true则不释放index
    //自动换房主,如果没人则自动关闭群
    //返回ExitGroup(剩余人数) 或 错误（<0)
    int ExitGroup(_ClientInfo *pClientInfo, bool bKeepGroupIndex, bool groupWillClose = false);

    //关闭群
    int CloseGroup(_ClientsGroupInfo *pClientsGroupInfo, _ClientInfo *pClientInfo = nullptr);

    //设置房主
    //参数:同pGroup->ChangeGroupMaster
    //返回:同pGroup->ChangeGroupMaster
    int SetGroupMaster(int index, _ClientsGroupInfo *pGroup, bool set = true);

    //产生并设置pGroup的 int32的ID(count为位数)
    qint32 CreateGroupHashID(int count);


    //断开客户
    //code 是断开码
    //serverForce 是否由服务器强制关闭，还是发送给客户端来关闭
    int DisconnectClient(_ClientInfo *pClientInfo, qint32 code, bool serverForce = false)
    {
        if(pClientInfo == nullptr)
            return -1;

        if(serverForce)
        {
            m_Server.m_IOCPModel.Close(pClientInfo->m_SocketContext);
        }
        else
        {
            m_Server.m_IOCPModel.sendData(pClientInfo, TRANSMIT_GROUP_TYPE)
                    << (qint16)GAME_SERVER_RESPONSE
                    << (qint16)GAME_SERVER_CLIENT
                    << (qint16)GAME_SERVER_CLIENT_DISCONNECT
                    << code;
            m_Server.m_IOCPModel.send(pClientInfo);
        }

        pClientInfo->m_bDisconnected = true;

        return 0;
    }
//其他
public:
    //信息
    virtual void Info(QString msg);// Q_DECL_OVERRIDE;
    //调试信息
    virtual void Debug(QString msg);// Q_DECL_OVERRIDE;
    //警告信息
    virtual void Warning(QString msg);// Q_DECL_OVERRIDE;
    //错误信息
    virtual void Critical(QString msg);// Q_DECL_OVERRIDE;



//游戏函数
public:
    //返回false：不改变积分
    //achieve：(0是强退游戏；)1是获胜；2是失败；3是逃跑
    //bool UpdateScore(_ClientInfo *pClientInfo, bool bNetPlay, qint16 achieve, qint32 scoreAdd = 0);



//回调函数
public:
//IOCP的Stop回调函数，必须用队列来处理（因为队列中还有其他Recv、Send、Accept、Close等没处理）。
//主线程调用
    static void FUNCTION_CALL_TYPE fnStopCallBack(void *param)
    {
        GameServer *GS = (GameServer*)param;
        QMetaObject::invokeMethod(GS, "__StopCallback", Qt::QueuedConnection);
    }

    static void FUNCTION_CALL_TYPE fnStopCallBack_UDP(void *param)
    {
        GameServer *GS = (GameServer*)param;
        QMetaObject::invokeMethod(GS, "__StopCallback_UDP", Qt::QueuedConnection);
    }


    //加入房间时，遍历所有房间的回调函数的条件
    //主线程调用
    static bool fnJoinGroupCallBack(_ClientInfo* clientInfo, _ClientsGroupInfo *groupInfo,  void *param)
    {
        _GameUserData *pGameUserData = (_GameUserData*)(clientInfo->m_pClientExtraData);
        //if(((_GameGroup*)groupInfo->m_pClientsGroupExtraData)->m_nType == pGameUserData->m_nType)
            return true;
        //else
        //    return false;
    }


public:
//4个SocketExtraData回调(IOCP池回调)
//注意:这4个函数是IOCP回调的,除了Unset是1个线程(主线程)调用外,其他3个都会在不同的线程内调用!!!所以注意内容

    //新建Socket时的ExtraData
    static void* FUNCTION_CALL_TYPE Fn_IOCP_SetSocketExtraData_Callback()
    {
        qDebug() << "[GameServer]Fn_IOCP_SetSocketExtraData_Callback";

        _ClientInfo *pClientInfo = (_ClientInfo*)Server::Fn_IOCP_SetSocketExtraData_Callback();
        pClientInfo->m_pClientExtraData = new _GameUserData;
        return pClientInfo;
    }

    //释放Socket时处理ExtraData
    static void FUNCTION_CALL_TYPE Fn_IOCP_UnsetSocketExtraData_Callback(void *pExtraData)
    {
        if(pExtraData != nullptr)
        {
            qDebug() << "[GameServer]Fn_IOCP_UnsetSocketExtraData_Callback";

            delete (_GameUserData*)(((_ClientInfo*)pExtraData)->m_pClientExtraData);
            Server::Fn_IOCP_UnsetSocketExtraData_Callback(pExtraData);
        }
        else
            qCritical() << "[!GameServer]Fn_IOCP_UnsetSocketExtraData_Callback ERROR!";
    }

    //使用池中Socket时的初始化
    static void FUNCTION_CALL_TYPE Fn_IOCP_Init_SocketExtraData_Callback(void *pExtraData)
    {
        if(pExtraData != nullptr)
        {
            qDebug() << "[GameServer]Fn_IOCP_Init_SocketExtraData_Callback";

            Server::Fn_IOCP_Init_SocketExtraData_Callback(pExtraData);
            ((_GameUserData*)(((_ClientInfo*)pExtraData)->m_pClientExtraData))->_pool_init();
        }
        else
            qCritical() << "[!GameServer]Fn_IOCP_Init_SocketExtraData_Callback ERROR!";
    }

    //释放池中Socket时的Release
    static void FUNCTION_CALL_TYPE Fn_IOCP_Release_SocketExtraData_Callback(void *pExtraData)
    {
        if(pExtraData != nullptr)
        {
            qDebug() << "[GameServer]Fn_IOCP_Release_SocketExtraData_Callback";

            ((_GameUserData*)(((_ClientInfo*)pExtraData)->m_pClientExtraData))->_pool_release();
            Server::Fn_IOCP_Release_SocketExtraData_Callback(pExtraData);
        }
        else
            qCritical() << "[!GameServer]Fn_IOCP_Release_SocketExtraData_Callback ERROR!";
    }


//4个GroupExtraData回调(Server的Group池回调)
//这4个函数是1个线程(主线程)调用的

    //新建Group时的新ExtraData
    static void* FUNCTION_CALL_TYPE Fn_SetGroupExtraData_Callback()
    {
        qDebug() << "[GameServer]Fn_SetGroupExtraData_Callback";

        _GameGroup *p = new _GameGroup;
        //p->m_pGameModel = new GameModel(p);
        return p;
    }

    //释放Group时的ExtraData析构
    static void FUNCTION_CALL_TYPE Fn_UnsetGroupExtraData_Callback(void *pGroupExtraData)
    {
        if(pGroupExtraData != nullptr)
        {
            qDebug() << "[GameServer]Fn_UnsetGroupExtraData_Callback";
            delete (_GameGroup*)pGroupExtraData;
        }
        else
            qCritical() << "[!GameServer]UnsetGroupExtraData Callback ERROR!";
    }

    //使用池中Group时的Init
    static void FUNCTION_CALL_TYPE Fn_InitGroupExtraData_Callback(void *pGroupExtraData)
    {
        qDebug() << "[GameServer]Fn_InitGroupExtraData_Callback";
        ((_GameGroup*)pGroupExtraData)->_pool_init();
    }

    //释放池中Group时的Release
    static void FUNCTION_CALL_TYPE Fn_ReleaseGroupExtraData_Callback(void *pGroupExtraData)
    {
        qDebug() << "[GameServer]Fn_ReleaseGroupExtraData_Callback";
        ((_GameGroup*)pGroupExtraData)->_pool_release();
    }



    /*void WriteLogToFile()
    {
        //m_pGameRecordLog->runCallBack(stFnWriteLogToFile, this, -1);

        QMetaObject::invokeMethod(m_pGameRecordLog,"runCallBack"
                                  ,Qt::AutoConnection
                                  //,Q_RETURN_ARG(QVariant, v)
                                  ,Q_ARG(void*, (void*)stFnWriteLogToFile)
                                  ,Q_ARG(void*, this)
                                  ,Q_ARG(void*, this)
                                  ,Q_ARG(int, -1)
                                  );

    }
    static int stFnWriteLogToFile(void *param1, void *param2, int id) {
        GameServer * gameserver = (GameServer*)param1;
        int (GameServer::*pFnCallBack)(int) = (int (GameServer::*)(int))param2;
        return (gameserver->*pFnCallBack)(id);
    }*/




//数据成员
public:
//外部设置
    qint32 m_nFrameSendInterval;        //定时发送帧,<=0表示不用这个功能



public:
    //与数据库交互用户信息
    //DatabaseSwap m_DatabaseSwap;

    //服务对象
    Server m_Server;
    Database *m_pDatabase;  //进行数据库操作
    //LongTask *m_pGameRecordLog; //进行日志记录

    UDPIOCP_Pleafles *m_pUDPIOCPModel;

protected:
    QHash<qint32,QUuid> m_hashNumberGroups;    //用数字来找房间,同m_mapGroups一样,同时操作(insert和remove)
    //QHash<QString,qint32> m_hashStringGroups;    //用字符串（登录名）来找房间,同m_mapGroups一样,同时操作(insert和remove)

    QMultiHash<quint32,_ClientInfo*> m_hashAllClientInfo;   //UserGameID找客户(已登录),用Multi的原因是 同一客户登录时,新客户先插入,旧客户必须要等回调函数才能删除.


    //bool m_bExit;               //退出服务器
    //暂时不用
    _ServerType m_ServerType;       //服务器类型(游戏服务器则会:用户强退扣分)
    int m_nRecordUserOnlineLog;     //是否记录 用户登录时间


//私有数据成员
private:
    Ui::GameServer *ui;

};

#endif // GAMESERVER_H
